﻿using ElasticSearchTest.Model;
using Nest;
using PMS.Search.Domain.Entities;
using PMS.Search.Domain.QueryModel;
using PMS.Search.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ElasticSearchTest
{
    public class EvaluationEsService
    {
        private readonly EsClient _client;
        private readonly EsIndexConfig.Index _index = EsIndexConfig.Instance.EvaluationIndex;

        public EvaluationEsService(EsClient client)
        {
            _client = client;
        }


        public PaginationModel<SearchEvaluation> SearchEvaluations(SearchEvaluationQueryModel queryModel)
        {
            var keyword = queryModel.Keyword;
            var orderBy = queryModel.OrderBy;
            var pageIndex = queryModel.PageIndex;
            var pageSize = queryModel.PageSize;

            int from = (pageIndex - 1) * pageSize;
            int size = pageSize;

            var search = new SearchDescriptor<SearchEvaluation>()
              .Index(_index.SearchIndex)
              .From(from)
              .Size(size)
              .Sort(SearchPUV.GetSortDesc<SearchEvaluation>(orderBy, "modifyDateTime"))
              ;
            var shouldQuerys = new List<Func<QueryContainerDescriptor<SearchEvaluation>, QueryContainer>>
            {
                q => q.Term(t => t.Field("title").Value(keyword).Boost(10))
            };

            Fields fields = Infer.Fields("title.pinyin", "title.keyword");
            if (!queryModel.SearchTitleOnly)
            {
                fields = Infer.Fields("title.pinyin", "title.keyword", "courseName.pinyin", "courseName.keyword", "orgName.pinyin", "orgName.keyword");
                shouldQuerys.Add(q => q.Term(t => t.Field("courseName").Value(keyword).Boost(10)));
                shouldQuerys.Add(q => q.Term(t => t.Field("orgName").Value(keyword).Boost(10)));
                shouldQuerys.Add(q => q.Match(t => t.Field("orgName.keyword").Query(keyword).Boost(5)));
            }

            search.Query(q =>
                q.Bool(b =>
                    b.Must(
                        m => m.Term(t => t.Field(f => f.IsValid).Value(1)),
                        m => m.Term(t => t.Field(f => f.Status).Value(1)),
                        m => m.MultiMatch(mm => new MultiMatchQuery()
                        {
                            Fields = fields,
                            Query = keyword
                        })
                    ).Should(shouldQuerys)
                ));

            var result = _client.GetClient().Search<SearchEvaluation>(search);

            var data = result.Hits.Select(s => s.Source).ToList();

            return PaginationModel.Build(data, result.Total);
        }

        /// <summary>
        /// 评测
        /// </summary>
        public CreateIndexResponse CreateIndex()
        {
            var resp = _client.GetClient().Indices.Delete(_index.Name);
            var createIndexResponse = _client.GetClient().Indices
                .Create(_index.Name, c => c
                .Aliases(ad => ad.Alias(_index.Alias))
                .Settings(s => s
                    .Setting("max_ngram_diff", 20)
                    .Setting("max_result_window", 500000)
                    .Analysis(AnalyzeBuilder.GetAnalysis())
                )
                .Map<SearchEvaluation>(mm => mm
                .Properties(p => p
                    .Keyword(t => t.Name(n => n.Id))
                    .Number(t => t.Name(n => n.No))
                    .Text(t => t.Name(n => n.Title)
                         .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("keyword")
                                    .Analyzer(AnalyzeBuilder.KeywordPinyinNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                        )
                    )
                    .Number(t => t.Name(n => n.Mode))
                    .Number(t => t.Name(n => n.IsPlaintext))
                    .Number(t => t.Name(n => n.Stick))
                    .Number(t => t.Name(n => n.Status))
                    .Number(t => t.Name(n => n.IsOfficial))
                    .Keyword(t => t.Name(n => n.SpecialId))
                    .Number(t => t.Name(n => n.SpecialNo))
                    .Text(t => t.Name(n => n.SpecialName)
                         .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                        )
                    )
                    .Number(t => t.Name(n => n.SpecialStatus))
                    .Keyword(t => t.Name(n => n.OrgId))
                    .Number(t => t.Name(n => n.OrgNo))
                    .Text(t => t.Name(n => n.OrgName)
                         .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("keyword")
                                    .Analyzer(AnalyzeBuilder.KeywordPinyinNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                        )
                    )
                    .Number(t => t.Name(n => n.OrgIsAuthenticated))
                    .Text(t => t.Name(n => n.OrgDesc)
                         .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                        )
                    )
                    .Text(t => t.Name(n => n.OrgSubdesc)
                         .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                        )
                    )
                    .Number(t => t.Name(n => n.OrgStatus))
                    .Number(t => t.Name(n => n.CourseNo))
                    .Keyword(t => t.Name(n => n.CourseId))
                    .Number(t => t.Name(n => n.CourseNo))
                    .Text(t => t.Name(n => n.CourseName)
                         .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("keyword")
                                    .Analyzer(AnalyzeBuilder.KeywordPinyinNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                        )
                    )
                    .Number(t => t.Name(n => n.Price))
                    .Keyword(t => t.Name(n => n.CourseMode).Fields(ff => ff.Number(fk => fk.Name("text"))))
                    .Number(t => t.Name(n => n.MinAge))
                    .Number(t => t.Name(n => n.MaxAge))
                    .Number(t => t.Name(n => n.Subject))
                    .Date(t => t.Name(n => n.ModifyDateTime))
                    .Number(t => t.Name(n => n.IsValid))
                    .Boolean(t => t.Name(n => n.IsDeleted))
                    .Number(t => t.Name(n => n.SpecialIsValid))
                    .Number(t => t.Name(n => n.OrgIsValid))
                    .Number(t => t.Name(n => n.CourseIsValid))
                    .Number(t => t.Name(n => n.Pv))
                    .Number(t => t.Name(n => n.Uv))
                    ))
            );
            return createIndexResponse;
        }
    }
}
